
/*
这类自己写的RAM模块Quartus很有可能不会将其映射到M10K内存模块上来实现，直接导致系统资源不够或编译时间较长。
在实际上板的代码中建议对于容量大于64k的存储都采用IP核生成的RAM。
*/

module testdmem(
  byteena_a,  // 字节使能信号，控制数据输入的哪些字节是有效的
  data,       // 输入数据，32位宽度
  rdaddress,  // 读地址，15位宽度
  rdclock,    // 读操作时钟信号
  wraddress,  // 写地址，15位宽度
  wrclock,    // 写操作时钟信号
  wren,       // 写使能信号，当为高电平时允许写操作
  q);         // 输出数据，32位宽度

  // 定义输入输出端口的数据类型和位宽
  input   [3:0]   byteena_a;
  input       [31:0]  data;
  input       [14:0]  rdaddress;
  input       rdclock;
  input       [14:0]  wraddress;
  input       wrclock;
  input       wren;
  output reg  [31:0]  q;

  // 定义内部使用的寄存器变量
  reg  [31:0] tempout;  // 用于暂存读出的数据
  wire [31:0] tempin;   // 用于暂存待写入的数据
  reg [31:0] ram [32767:0]; // 双端口RAM，共32768个地址，每个地址32位宽度

  // 读操作逻辑，在rdclock的上升沿触发
  always@(posedge rdclock)
  begin
    if(wren) // 如果当前是写操作
      tempout<=ram[wraddress]; // 将写地址对应的数据读出到tempout中
    else
      q <= ram[rdaddress]; // 否则，将读地址对应的数据读出到输出端口q中
  end

  // 根据字节使能信号选择输入数据或tempout中的对应字节
  assign tempin[7:0]   = (byteena_a[0])? data[7:0]  : tempout[7:0];
  assign tempin[15:8]  = (byteena_a[1])? data[15:8] : tempout[15:8];
  assign tempin[23:16] = (byteena_a[2])? data[23:16]: tempout[23:16];
  assign tempin[31:24] = (byteena_a[3])? data[31:24]: tempout[31:24];

  // 写操作逻辑，在wrclock的上升沿触发
  always@(posedge wrclock)
  begin
    if(wren) 
    begin
      ram[wraddress]<=tempin; // 将tempin中的数据写入到写地址对应的RAM位置中
    end
  end
endmodule